using System;
using System.ComponentModel;

namespace needle.Services.astra.Common
{
	/// <summary>
	/// Uri with default value. 
	/// </summary>
	public abstract class UriContainer : INotifyPropertyChanged
	{
		/// <summary>
		/// Constructor.
		/// </summary>
		public UriContainer()
		{
		}
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="uri">See <see cref="Uri"/>.</param>
		public UriContainer(Uri uri)
		{
			this.Uri = uri;
		}

		/// <summary>
		/// Implicit conversion.
		/// </summary>
		/// <param name="uriContainer">Uri container.</param>
		/// <returns><paramref name="uriContainer"/>.<see cref="ActualUri"/>.</returns>
		public static implicit operator Uri(UriContainer uriContainer)
		{
			if (uriContainer == null)
				return null;
			else
				return uriContainer.ActualUri;
		}

		/// <summary>
		/// Actual uri.
		/// </summary>
		/// <value>
		/// If <see cref="Uri"/> is null, returns <see cref="DefaultUri"/>, otherwise <see cref="Uri"/>.
		/// </value>
		public Uri ActualUri
		{
			get
			{
				if (this.Uri == null)
					return this.DefaultUri;
				else
					return this.Uri;
			}
		}
		/// <summary>
		/// Uri.
		/// </summary>
		/// <value>Default: null.</value>
		public Uri Uri
		{
			get { return _uri; }
			set
			{
				if (object.Equals(_uri, value))
					return;
				_uri = value;
				OnPropertyChanged("Uri");
				OnPropertyChanged("ActualUri");
			}
		}
		/// <summary>
		/// Default uri.
		/// </summary>
		public abstract Uri DefaultUri
		{
			get;
		}

		public override bool Equals(object obj)
		{
			return
				obj is UriContainer && this.Uri == (obj as UriContainer).Uri ||
				obj is Uri && this.ActualUri == obj as Uri;
		}

        public override int GetHashCode() {
            return base.GetHashCode();
        } 

		#region INotifyPropertyChanged Members

		/// <summary>
		/// Fired when a property is changed.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Fires <see cref="PropertyChanged"/> event.
		/// </summary>
		/// <param name="propertyName">Property name.</param>
		protected virtual void OnPropertyChanged(string propertyName)
		{
			if (this.PropertyChanged != null)
				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}

		#endregion

		/// <summary>
		/// See <see cref="Uri"/>.
		/// </summary>
		private Uri _uri;
	}
}
